#!PERL_EXE PERL_FLG
#
# Written by jfd@Fri Sep  4 17:45:24 WDT 1998
# Program converts restraints to AQUA format

use CGI qw(:all);
$q = new CGI;
$| = 1; # piping hot

# INITIALIZE:

# SITE DEPENDANT
$serv_loc        = "AQUA_LOC/Aqua/server/";
$serv_dir        = "AQUA_DIR/Aqua/server/";

$cgi_bin_loc     = "CGI_LOC/Aqua/";
$cgi_bin_dir     = "CGI_DIR/Aqua/";

$tmp_loc         = "TMP_LOC/Aqua/";
$tmp_dir         = "TMP_DIR/Aqua/";

$webmaster       = 'WEBMASTER';


# SITE INDEPENDENT
$author          = "jurgen\@bmrb.wisc.edu";

$overview        = "overview.html";
$logfile         = "server.log";


# PROGRAM SPECIFIC
$server          = $serv_loc . "qconvert.html"; 
$log_hosts       = $tmp_dir  . "logs/qconvert";
$finished        = "finished";     # showing the csh script was finished
$icon            = "qconvert.gif";
$debug           = "f";            # t or f; 
$seconds         = 3600;           # Seconds before removing everything.
$cal_time_secs   = 30;             # Seconds before calculation should be 
                                   # finished.




beginning();
process_options();

write_uploaded_file_to_disk('RST_FILE', '-', $random_dir . "restraints.rst");

show_wait_message();
log_remotehost();
do_calculation();
make_result_overview();
show_result_overview();
ending();



sub beginning {    
    
    $giffie = $serv_loc . "img/$icon";
    
    print $q->header('text/html');
    
    umask 0000; # assists in setting new permissions

    print   
	$q->start_html( -"title"    =>'Conversion of NMR restraints to AQUA format', 
			-"author"   =>$author, 
			-"BGCOLOR"  =>"white"), "\n"; 
    print   
	img {-src=>$giffie,-align=>'RIGHT'};
    print
        "\n", 
	h1( a({href=>$serv_loc},  "Aqua server"       ) ), "\n", 
	h2( a({href=>$server},    "Conversion of NMR restraints to AQUA format") ), "\n",
	br, br, hr;
	
    print
	p("Your query has been received. Please wait.\n");

#
# These variables will be used throughout the program
#    

    ( $random_numbers, $random_dir ) = create_tmp_random_dir( $tmp_dir );

    $log_file = $random_dir . $logfile;    
    open (LOGFILE, ">$log_file" ) || 
	end_error ("can not open a writable file: [$log_file]\n$!");

# Just print them to use them, so the compiler doesn't warn.
    print LOGFILE 
	"REMARK starting qconvert.pl at ", `date`, "\n\n",
	"ENVIRONMENT : serv_loc    $serv_loc\n", 
	"ENVIRONMENT : serv_dir    $serv_dir\n", 
	"ENVIRONMENT : tmp_dir     $tmp_dir\n", 
	"ENVIRONMENT : cgi_bin_loc $cgi_bin_loc\n", 
	"ENVIRONMENT : cgi_bin_dir $cgi_bin_dir\n\n";
}


sub process_options {
    
    if ( $debug eq "t" ) {
	print p("You have submitted the following data:");
	print $q->dump;
    }

    @option_array = qw( automatic disgeo xplor biosym diana_disman );
    check_option_strings ( Rst_type, @option_array );
}


sub show_wait_message{

    my ( $JSCRIPT ) =<<END;
	var seconds = 0
	var minutes = 0
	var hours = 0
	var timerID = setTimeout("showtime()",1000);

	function showtime() { 
	  seconds ++;
	  if (seconds == 60) {
	   seconds=0;
	   minutes ++;
	  }
	  if (minutes == 60){
	    minutes=0;
	    hours ++;
	  }
	  if (hours == 24){
	    hours = 0;
	  }
	  var timeValue =""+(hours)
	  timeValue +=((minutes < 10) ? ":0" : ":")+minutes
	  timeValue +=((seconds < 10) ? ":0":":")+seconds
	  document.clock.face.value = timeValue;
	  timerID = setTimeout("showtime()",1000);
	}
END

    print
	"<SCRIPT LANGUAGE=\"JavaScript\"><!-- Hide script>\n", 
	$JSCRIPT,
	"// End script hiding --></SCRIPT>";

    print
	hr,
	p(  "The calculation time should be less than $cal_time_secs seconds.\n" );

    print
	br,
	"<form name=\"clock\" onSubmit=\"0\">\n", 
	"<input type=\"text\" name=\"face\" size=8 value=\"0:00:00\">\n", 
	"</input></form>\n", 
	hr;
	
}


sub do_calculation{

    my ( $output );    
    my ( $number )          = 0;
    my ( $sleep_time )      = 1;

    my ( $prog )            = $cgi_bin_dir . "qconvert.csh";
    my ( $finished_file )   = $random_dir . $finished;
    my ( $type )            = $q->param( 'Rst_type' );

    $log = $random_dir . "qconvert.log";
    
    $output = `($prog $random_numbers $type) > $log 2>&1 &`;
	 
    if ( $output ) {
	print 
	    pre ( "\nUnexpected output:\n", $output, "\n" ), hr;
    }

    while ( $number < $cal_time_secs ) {
	$number += $sleep_time;

	if ( -e $finished_file ) {
	    last;
	}
	print "<CARIN>"; #bogus to keep the browser from a timeout.
	sleep $sleep_time;	
    }    
}


sub make_result_overview {

    my ( $remove_dir_link ) = $cgi_bin_loc . "remover.pl?" . $random_numbers;
    my ( $overview_file )   = $random_dir . $overview;
    my ( $succes       )    = get_item_file( $log, 4, "QCONVERT - result is");
    my ( $qconvert_log )    = "qconvert.log";

    @file_list =     qw ( noe hb ss dis tor );

    @desc_list = (  "NOE distance restraints file",
		    "Hydrogen bond restraints file",
		    "Disulphide restraints file", 
		    "Generic distance restraints file", 
		    "Torsion angle restraints file" );  
    
    print LOGFILE "REMARK update overview\n";
	
    open (OVERVIEW, ">$overview_file" ) || 
	end_error ("can not open a writable file: [$overview_file]\n$!");
		
    print OVERVIEW
	$q->start_html( -"title"    =>'Conversion of NMR restraints to AQUA format', 
			-"author"   =>$author, 
			-"BGCOLOR"  =>"white"), "\n"; 
    print OVERVIEW
	img {-src=>$giffie,-align=>'RIGHT'};

    print OVERVIEW
        "\n", 
	h1( a({href=>$serv_loc},  "Aqua server"       ) ), "\n", 
	h2( a({href=>$server}, "Conversion of NMR restraints to AQUA format") ), "\n",
	br, br, hr;
	
    if ( $succes eq "true" ) {

	print OVERVIEW
	    h3( b("Converted restraint files\n") );

	$tellertje = 0;

	print OVERVIEW "<TABLE BORDER CELLSPACING=0 CELLPADDING=10 >\n";

	foreach $file ( @file_list ) {

	    $ref	    = "restraints." . $file;
	    $result_file    = $random_dir . $ref;

	    print OVERVIEW "<TR>\n";
	    if ( -r $result_file ) {

		open (IN, "$result_file" ) || 
		    end_error ("can not open a readable file: $result_file $!");
		
		$temp = <IN>;
		$temp = <IN>;

		@line = split (/ +/, $temp ) ;
		$count = $line[1]; # Get count (second) record

		close (IN) || 
		    end_error("can't close file: $result_file $!");    
		
		print OVERVIEW
		    td ( a( {href=>$ref}, $ref ) ), 
		    td ( i($count." items") ), "\n";
	    } else {
		print OVERVIEW
		    td ( $ref ), 
		    td ( i("No items") ), "\n";
	    }
	    
	    print OVERVIEW
		td( $desc_list[ $tellertje++ ]), "</TR>\n";
	}
	
	print OVERVIEW "</TABLE>\n";
		    
	print OVERVIEW
	    p( b("Log files"),
	       li( a( {href=>$qconvert_log}, "qconvert log file"." ".i("(informative log)") )), 
	    "\n\n" );

       print OVERVIEW
	    hr,
	    p("Please save the necessary files to your local disk.");
	    	    
	print LOGFILE "REMARK presented results to overview\n";
	    	    
    } else {
    
	print OVERVIEW
	     h1("NO RESULTS"),
	     p("ERROR occured or script didn't finish within time limits, sorry."),
	     p(  
		"Look for possible causes of the error in a log file with the",
		$q->a({href=>"$qconvert_log"},"details"),
                "(might not be present)",
                "alternatively pick your favorite file from the working directory", 
		$q->a({href=>"."},"here."),
		"Contact us if you like.",
	        "\n\n" );

	print LOGFILE "ERROR in qconvert script\n";
    }

    print OVERVIEW
	    hr,
	    p("Please click ",
		$q->a({href=>$remove_dir_link}, "here"),
		"after you are finished.",
		"This will remove the files on our disk.",
		"After 1 hour the files will be deleted",
		"automatically anyway.");

    print OVERVIEW
	hr,
	p("Contact the \n", 
	    a({href=>"mailto:".$author}, "author"), "or\n",
	    a({href=>"mailto:".$webmaster}, "webmaster\n"),
	    "for help, when required.\n"), 
	$q->end_html, 
	"\n";
		
    close (OVERVIEW) || end_error("can't close file: $overview_file: $!");		
}


sub show_result_overview{
    my ( $overview_file ) = $tmp_loc . $random_numbers  . "/" . $overview;
    my ( $JSCRIPT ) =<<END;
// Just simply stop the clock by killing the function.
function showtime () { 
} 
END

    print
	"<SCRIPT LANGUAGE=\"JavaScript\"><!-- Hide script>\n", 
	$JSCRIPT,
	"// End script hiding --></SCRIPT>";

    print
	p("Finished the calculations\n"), 
	p("You can now proceed to the\n", 
	a( {href=>$overview_file}, "results"), ".\n");
}


sub end_error {
    my ( $message ) = @_;

    print 
	pre("\n\nERROR: $message\n\n");

    ending();
}


sub ending {
    print 
	hr,
	p("Contact the \n", 
	    a({href=>"mailto:".$author}, "author"), "or\n",
	    a({href=>"mailto:".$webmaster}, "webmaster\n"),
	    "for help, when required.\n"), 
	$q->end_html, 
	"\n";
	   
    close_possible_file( \*LOGFILE );
    
    exit(0);
}




#
# ***** COMMON SUBROUTINES *******
#
# Can be used without reference to the variables in the main.
#


sub create_tmp_random_dir {
#
# Creates a sub-dir in the given dir with a random six number figure
#

    my ( $main_dir ) = @_;
    my ( $random_dir, $six_random_numbers );
        
    if ( !(-e $main_dir) ) {
	end_error ("No main dir: [$main_dir]");	    
    }

    $done = "false";
    while ( $done eq "false" ) {
    
	$six_random_numbers = create_random();   
	$random_dir = $main_dir . $six_random_numbers . "/";
		
	if ( -e $random_dir ) {
	    if ( $debug eq "t" ) {
		print "Directory is already present: ", $random_dir, "\n";	
	    }
	} else {
	    if ( $debug eq "t" ) {
		print "Making writable temporary directory: ", $random_dir, "\n";
	    }
	    mkdir( $random_dir, 0777 ) ||	
		end_error ("can not create dir: [$random_dir]\n$!");
	    $done = "true";

	    delayed_remove_dir( $random_dir, $seconds );
	}
    }
    
    return ( $six_random_numbers, $random_dir );
}



sub close_possible_file {
#
# File doesn't need to exist
#
    my ( $fh ) = shift;

    close ( $fh )
}


sub create_random {
    my ( $random_number ) = rand(10000000000);    
    return( substr ( $random_number, 0, 6) );
}


sub write_uploaded_file_to_disk {

    my ( $uploaded_file, $uploaded_type, $file_name ) = @_;

    if ( !defined( $uploaded_file ) ) {
	end_error "no file given to save";
    }
    
    if ( $uploaded_file eq "" ) {
	end_error "no filename given to save";
    }
    
    if ( !defined( $uploaded_type ) ) {
	end_error "no file type given to save";
    }

    if ( !defined( $file_name ) ) {
	end_error "no file name given to save";
    }

    if ( defined( $q->param( $uploaded_file ) ) ) {

	$file_handle = $q->param( $uploaded_file );
	if ( $debug eq "t" ) {
	    print "Found uploaded file: ", $file_handle, "\n";
	}
	
	if ( !defined ( $q->uploadInfo( $file_handle ) ) ) {
	    end_error "File is not uploaded";
	}
	
	$type     = $q->uploadInfo( $file_handle )->{'Content-Type'};
	if ( $debug eq "t" && defined($type) ) {
	    print "of type: ",  $type,  "\n";
	}

    } else {
	end_error "Didn't find: [$uploaded_file]\n";	
    }
    
    unless ( $uploaded_type eq '-' ) {
	if ( !( $type eq $uploaded_type ) ) {
	    end_error "Type expected: $uploaded_type instead found $type\n";
	}
    }
            
    if ( $debug eq "t" ) {
	print "Opening file: ", $file_name, "\n";
    }
    
    open (OUTFILE, ">$file_name" ) || 
	end_error "can not open a writable file: [$file_name]\n$!";

    $remotehost = remote_host();
    if ( defined ( $remotehost ) ) {
	print LOGFILE "REMARK File $file_handle from $remotehost\n";
    }
    
    $servername = server_name (); 
    if ( defined ( $servername ) ) {
	print LOGFILE "REMARK Accepted by $servername at ".`date`;
    }
	    
    while ($bytesread=read($file_handle,$buffer,1024)) {
        print OUTFILE $buffer;
	$total_bytes_read += $bytesread;
    }

    if ( defined ($total_bytes_read) && ( $debug eq "t" ) ) {
	printf "Processed %d bytes\n", $total_bytes_read;
    }
    
    close (OUTFILE) ||	end_error("can't close out_file: [$file_name]\n$!");
}


sub delayed_remove_dir {
    my ( $dir, $seconds ) = @_;
        
    if ( defined ( $dir ) ) {
	if ( -e $dir ) {
	    `(sleep $seconds; /bin/rm -rf $dir) > /dev/null 2>&1 &`;
	}
    }
}

sub check_option_strings {
    my ( $option_string, @option_array );
    ( $option_string, @option_array ) = @_;

    if ( !defined( $option_string ) ) {
	end_error ("Sub check_option_string: no option given");
    }
    if ( ! @option_array ) {
	end_error ("Sub check_option_string: no possible options given(0)");
    }
    
    $number_options = @option_array;
    if ( $number_options < 1 ) {
	end_error ("Sub check_option_string: no possible options given:".
		    $number_options);
    }

    if ( defined( $q->param( $option_string ) ) ) {

	if ( $debug eq "t" ) {
	    print "Found option: ", $option_string, "\n";
	}

	$value = $q->param( $option_string );
	
	if ( $debug eq "t" ) {
	    print "With value: ", $value, "\n";
	}
	
	foreach $option ( @option_array ) {
	    if ( $value =~ $option ) {
		return(0);
	    }
	}
	
	end_error ("The value given for option $option_string".
		    "\nis not available.\n".
		    "Available are: @option_array.");

    } else {
	end_error ("Sub check_option_string:".
			"option $option_string not presented\n");	
    }

}




sub get_item_file {

# Returns the item on the first line containing the search string
# items are number starting from 0

    my ( $file, $item_number, @search_string ) = @_;
    my ( @Fld );
    
    if ( $item_number < 1 ) {
	end_error ("item number: $item_number too small\n");	
    }

    $search_string = join ' ', @search_string ;
        
    open (FILE, "$file" ) || 
	return ( "can not open readable file: [$file]\n$!");
	
    while ( <FILE> ) {
	if ( $_ =~ $search_string ) {

		@Fld = split ( /\s+/ );

		if ( $#Fld < $item_number ) {
		    return ( "item_number too big\n");	
		}

		close ( FILE );
		return ( $Fld[ $item_number ] );

	    }
    }
    close ( FILE );
    
    return ( "Item found" );
}


sub log_remotehost {

# $remotehost and $file_handle are set in sub write_uploaded_file_to_disk
# $log_hosts is from main

    open (LOGHOST, ">>$log_hosts" ) || 
	end_error ("can not open a appendable file: [$log_hosts]\n$!");
		
    if ( defined ( $remotehost ) ) {
	printf LOGHOST ("%-40s ", $remotehost );
    } else {
	printf LOGHOST ("%-40s ", "UNKNOWN" );
    }
    $date_str = `date`;
	chomp($date_str);
    printf LOGHOST ("%-20s %-28s", $file_handle, $date_str);

    close ( LOGHOST );
}
